#pragma
#include"Socket.hpp"
#include"Log.hpp"
#include<iostream>
#include<pthread.h>
#include<string>
#include<sys/wait.h>
#include<sys/types.h>
#include<vector>
#include<fstream>
#include<sstream>
#include<unordered_map>

using namespace std;
class HttpServer;

class ThreadData
{
public:
    ThreadData(int fd,HttpServer* s):sockfd(fd),sur(s)
    {

    }
    
public:
    int sockfd;
    HttpServer* sur;
};

static const int defaultport=8082;
static const string sep="\r\n";
const string wwwroot="./wwwroot";//根目录
const string homepage="index.html";

class HttpRequest
{
public:
//反例化
    void Deserialize(std::string req)
    {
        while(true)
        {
            ssize_t pos=req.find(sep);
            if(pos==std::string::npos)  break;
            std::string temp=req.substr(0,pos);
            if(temp.empty())    break;
            req_header.push_back(temp);
            req.erase(0,pos+req.size());
        }
        text=req;
    }
    //解析
    void Prase()
    {
        stringstream s(req_header[0]);
        s>>method>>url>>http_version;
        file_path=wwwroot;
        //如果等于根目录
        if(url=="/"||url=="/index.html")
        {
            file_path +="/";
            file_path += homepage;
        }
        else file_path+=url;//  a/b/c/d.html

    }
    void DeBugPrint()
    {
        for(auto& i:req_header)
        {
            cout<<"=============";
            cout<<i<<"\n\n";
        }
        cout<<text<<endl;

    }
public:
    vector<std::string> req_header;
    std::string text;

    //解析之后的结果
    string method;
    string url;
    string http_version;
    string file_path;
};
class HttpServer
{
public:
    HttpServer(uint16_t port=defaultport):port_(port)
    {
        content_type.insert("./html","");
    }
    bool Start()
    {
        listenfd_.Socket();
        listenfd_.Bind(port_);
        listenfd_.Listen();
        for(;;)
        {
            string clintip;
            uint16_t clintport;
            int sockfd=listenfd_.Accept(&clintip,&clintport);
            if(sockfd<0)
            {
                continue;
            }
            lg(Fatal,"get a new connect,sockfd:%d",sockfd);
            pthread_t pid;
            ThreadData* td=new ThreadData(sockfd,this);
            td->sockfd=sockfd;
            pthread_create(&pid,nullptr,ThreadRun,&td);

        }
    }
    static std::string ReadHttpContent(const std::string& htmlpath)
    {
        std::ifstream in(htmlpath);
        if(!in.is_open())    return "404";
        
        std::string content;
        std::string line;
        while(std::getline(in,line))
        {
            content+=line;
        }
        in.close();

        return content;
    }
    string SuffixToDesc(const string& sufex)
    {
        auto iter=content_type.find(sufex);
        if(iter==content_type.end())    return content_type[".html"];
        else return content_type[sufex];

    }
    void HandleHttp(int sockfd)
    {
        
        char buffer[10240];
        //ThreadData* td=new ThreadData();
        ssize_t n=recv(sockfd,buffer,sizeof(buffer)-1,0);
        if(n<0)
        {
            buffer[n]=0;
            cout<<buffer<<endl;
            //返回相应的结果


            HttpRequest rq;
            rq.Deserialize(buffer);
            rq.Prase();
            //std::string text="<html><body><h3>hello</h3></body></html>";
            std::string text=ReadHttpContent(rq.file_path);

            std::string reposnse_line="HTTP/1.0 200 ok\r\n";
            std::string reposnse_header="Content-Length: ";

            reposnse_header+=std::to_string(text.size());
            reposnse_header+="\r\n";
            reposnse_header+="content_type: ";
            reposnse_header+= SuffixToDesc(rq.file_path);
        
            std::string blank_line="\r\n";

            std::string reponse=reposnse_line;
            reponse+=reposnse_header;
            reponse+=blank_line;
            reponse+=text;

            send(sockfd,reponse.c_str(),reponse.size(),0);
        }
        close(sockfd);


    }
    static void* ThreadRun(void* argc)
    {
        pthread_detach(pthread_self());
        ThreadData* td=static_cast<ThreadData*>(argc);

        td->sur->HandleHttp(td->sockfd);
        
        delete td;
        return nullptr;
    }
    ~HttpServer(){}
private:
    uint16_t port_;
    Sock listenfd_;
    unordered_map<std::string,std::string> content_type;
};